/*
 * File Name: AppContext.java
 *------------------------------------------------------------------------------
 * Copyright 2012 NCR Corporation
 *------------------------------------------------------------------------------
 * All revision information is updated automatically from source code control
 * change records - please do not manually edit.
 *------------------------------------------------------------------------------
 *
 *  $LastChangedRevision:: 1853                                     $
 *  $LastChangedBy:: rb250096                                       $
 *  $LastChangedDate:: 2012-03-21 23:04:58 -0400 (Wed, 21 Mar 2012) $
 */

package com.ncr.nep.dashboardcore.utils.client;

import java.util.HashMap;

import com.google.web.bindery.event.shared.EventBus;

/**
 * Singleton that provides a basic storage container for data that needs to be
 * available throughout the application.  This container can be used for storing
 * objects that should only be available as singletons plus any other arbitrary
 * key/value pairs.
 * 
 * @author rb250096
 * @version $Revision: 1853 $
 */
public class AppContext {

    //--------------------------------------------------------------------------
    //
    //  Fields
    //
    //--------------------------------------------------------------------------

    /**
     * The singleton instance.
     */
    private static AppContext instance = new AppContext();

    /**
     * Map used to store the key/value pairs in the context.
     */
    protected HashMap<Object, Object> map = new HashMap<Object, Object>();

    /**
     * EventBus instance that can be used throughout the application.
     */
    protected EventBus eventBus;

    //--------------------------------------------------------------------------
    //
    //  Constructors
    //
    //--------------------------------------------------------------------------

    /**
     * Constructor
     */
    protected AppContext() { }

    //--------------------------------------------------------------------------
    //
    //  Properties
    //
    //--------------------------------------------------------------------------

    /**
     * Gets the EventBus associated with the context.
     *
     * @return The EventBus object.
     */
    public static EventBus getEventBus() {
        return instance.eventBus;
    }

    /**
     * Sets the EventBus associated with the context.
     *
     * @param eventBus The EventBus object.
     */
    public static void setEventBus(EventBus eventBus) {
        instance.eventBus = eventBus;
    }

    //--------------------------------------------------------------------------
    //
    //  Methods
    //
    //--------------------------------------------------------------------------

    /**
     * Puts a value in the context.
     *
     * @param key The key used to retrieve the value later.
     * @param value The value to store in the context.
     */
    public static void put(Object key, Object value) {
        instance.map.put(key, value);
    }

    /**
     * Gets the value from the context with the specified key.
     *
     * @param key The key that was used to store the value in the context.
     * @param <T> The type of value referenced by the key.
     *
     * @return The value associated with the specified key, or null if there
     * is none.
     */
    @SuppressWarnings("unchecked")
    public static <T> T get(Object key) {
        Object value = instance.map.get(key);
        if(value == null) {
            return null;
        }
        else {
            return (T)value;
        }
    }

    /**
     * Removes the value associated with the specified key.
     *
     * @param key The key associated with the value to remove from the context.
     */
    public static void remove(Object key) {
        instance.map.remove(key);
    }

    /**
     * Removes all items from the context.
     */
    public static void clear() {
        instance.map.clear();
    }

    /**
     * Ensures that the object instance created by the <code>creator</code>
     * delegate is available in the context.  If it is not, the creator will be
     * invoked to create a new instance and add it to the context.
     *
     * @param creator Delegate that when invoked creates a new object instance
     *                and returns it.
     * @param valueClass The {@link Class} used as the key to add the
     *                   generated instance to the context; this will be used
     *                   to retrieve the instance via the {@link #get(Object)}
     *                   method.
     * @param <T> The type of object to be created by the creator and available
     *            in the context via <code>valueClass</code>.
     */
    public static <T> T ensureAvailable(
            Delegate<? extends T> creator,
            Class<T> valueClass) {
        if(!instance.map.containsKey(valueClass)) {
            T instance = creator.invoke();
            put(valueClass, instance);
        }

        return get(valueClass);
    }
}
